﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Helpers.cs" company="DHGMS Solutions">
//   Licensed under GNU General Public License version 2 (GPLv2)
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Dhgms.Nucleotide
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Text;

    using Dhgms.Nucleotide.PropertyInfo;

    /// <summary>
    /// Helpers helper methods for code generation
    /// </summary>
    public static class Helpers
    {
        /// <summary>
        /// The lazy randomizer.
        /// </summary>
        private static readonly Lazy<Random> LazyRandomizer = new Lazy<Random>(() => new Random((int)DateTime.Now.Ticks));

        #region Public Methods and Operators

        /// <summary>
        /// Generates a comment warning of modifying the generated file
        /// </summary>
        /// <returns>
        /// C# comment
        /// </returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public static string GetAutoGeneratedWarning()
        {
            var sb = new StringBuilder();
            sb.AppendLine("        // ********** WARNING **********");
            sb.AppendLine("        // This code is automatically generated! Any Changes you make to this file will be lost!");
            sb.AppendLine("        // To make changes edit the corresponding .tt file!");

            return sb.ToString();
        }

        /// <summary>
        /// Makes sure the first letter of the property name is upper case
        /// </summary>
        /// <param name="name">
        /// property name to check
        /// </param>
        /// <returns>
        /// cased property name
        /// </returns>
        public static string GetClassFieldName(string name)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }

            if (name.Length < 2)
            {
                throw new ArgumentException("Name too short", "name");
            }

            return name.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + name.Substring(1);
        }

        /// <summary>
        /// Generates the class header.
        /// Largely redundant, here because the C++ used it and because there are options to use it for sealing C# classes in future
        /// </summary>
        /// <param name="className">
        /// The name of the class
        /// </param>
        /// <returns>
        /// The get class header.
        /// </returns>
        public static string GetClassHeader(string className)
        {
            var sb = new StringBuilder();
            sb.AppendLine("public class " + className);
            return sb.ToString();
        }

        /// <summary>
        /// generates the IEquatable methods for an information class
        /// </summary>
        /// <param name="className">
        /// name of the class
        /// </param>
        /// <param name="baseClassName">
        /// The name of the base class
        /// </param>
        /// <param name="baseClassProperties">
        /// The properties of the base class
        /// </param>
        /// <returns>
        /// C# Code
        /// </returns>
        [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")]
        public static string GetIEquatableRegion(string className, string baseClassName, PropertyInfoBase[] baseClassProperties)
        {
            var sb = new StringBuilder();

            sb.AppendLine("#region IEquatable methods");
            sb.AppendLine(GetTabs(3) + "/// <summary>");
            sb.AppendLine(GetTabs(3) + "/// Checks if the current instance matches another of the same type");
            sb.AppendLine(GetTabs(3) + "/// </summary>");
            sb.AppendLine(GetTabs(3) + "/// <param name=\"other\">object to compare</param>");
            sb.AppendLine(GetTabs(3) + "/// <returns>true if equal, otherwise false</returns>");
            string modifier = (!string.IsNullOrWhiteSpace(baseClassName) && baseClassProperties != null
                               && baseClassProperties.Length > 0)
                                  ? null
                                  : "override ";
            sb.AppendLine(GetTabs(3) + "public " + modifier + "bool Equals(" + className + " other)");
            sb.AppendLine(GetTabs(3) + "{");
            sb.AppendLine(GetTabs(4) + "return this.CompareTo(other) == 0;");
            sb.AppendLine(GetTabs(3) + "}");
            sb.AppendLine(string.Empty);
            sb.AppendLine("#endregion");
            sb.AppendLine(string.Empty);

            return sb.ToString();
        }

        /// <summary>
        /// Generates the tabs at the beginning of a line
        /// </summary>
        /// <param name="tabs">
        /// number of tabs
        /// </param>
        /// <returns>
        /// string of tabs
        /// </returns>
        public static string GetTabs(int tabs)
        {
            var sb = new StringBuilder();
            int counter = 0;
            while (counter < tabs)
            {
                sb.Append("    ");
                counter++;
            }

            return sb.ToString();
        }

        /// <summary>
        /// Ensures the first letter of a property name is lower case for a variable
        /// </summary>
        /// <param name="name">
        /// Property Name to Convert
        /// </param>
        /// <returns>
        /// Cased variable name
        /// </returns>
        public static string GetVariableName(string name)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }

            if (name.Length < 2)
            {
                throw new ArgumentException("Name too short", "name");
            }

            return name.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + name.Substring(1);
        }

        /// <summary>
        /// Generate a random string.
        /// </summary>
        /// <param name="size">The length of the string.</param>
        /// <returns>A random string</returns>
        public static string GetRandomString(int size)
        {
            var builder = new StringBuilder();
            for (var i = 0; i < size; i++)
            {
                builder.Append((char)LazyRandomizer.Value.Next(65, 90));
            }

            return builder.ToString();
        }


        #endregion
    }
}